import logging
import os
from logging.handlers import RotatingFileHandler
from PySide6.QtCore import QObject, Signal
from src.config import app_config

# 1. Define a new log level for progress updates
PROGRESS_LEVEL_NUM = 15
logging.addLevelName(PROGRESS_LEVEL_NUM, "PROGRESS")

def progress(self, message, *args, **kws):
    if self.isEnabledFor(PROGRESS_LEVEL_NUM):
        self._log(PROGRESS_LEVEL_NUM, message, args, **kws)

logging.Logger.progress = progress

_logger_configured = False

class QLogHandler(logging.Handler, QObject):
    log_received = Signal(str)

    def __init__(self, level=logging.NOTSET):
        super().__init__(level=level)
        QObject.__init__(self)

    def emit(self, record):
        msg = self.format(record)
        self.log_received.emit(msg)

def setup_logger(log_file, ui_callback=None):
    """
    Sets up the root logger for file, console, and UI logging.
    - File logging is always at DEBUG level with a verbose format.
    - Console logging is at DEBUG (verbose) or INFO level based on the debug flag.
    - UI logging is at PROGRESS level and above with a simple format.
    This function is idempotent.
    """
    global _logger_configured
    logger = logging.getLogger()

    # Define formatters
    verbose_formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s'
    )
    console_formatter = logging.Formatter('%(levelname)s: %(message)s')
    ui_formatter = logging.Formatter('%(message)s')

    # --- Handle reconfiguration ---
    if _logger_configured:
        for handler in logger.handlers:
            if isinstance(handler, QLogHandler) and ui_callback:
                try:
                    handler.log_received.disconnect()
                except (TypeError, RuntimeError):
                    pass  # No connection existed
                handler.log_received.connect(ui_callback)
            
            # Update console handler level if debug flag changed
            elif isinstance(handler, logging.StreamHandler):
                is_debug = app_config.get('app.debug', False)
                handler.setLevel(logging.DEBUG if is_debug else logging.INFO)
                handler.setFormatter(verbose_formatter if is_debug else console_formatter)
        return

    # --- Initial configuration ---
    logger.setLevel(logging.DEBUG)  # Set root logger to the lowest level

    # Clear existing handlers to prevent duplicates
    if logger.hasHandlers():
        logger.handlers.clear()

    # --- File Handler ---
    # Always logs DEBUG and above with verbose details.
    log_dir = os.path.dirname(log_file)
    if log_dir:  # Only create directories if a path is specified
        os.makedirs(log_dir, exist_ok=True)
    file_handler = RotatingFileHandler(log_file, maxBytes=5*1024*1024, backupCount=5, encoding='utf-8')
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(verbose_formatter)
    logger.addHandler(file_handler)

    # --- Console Handler ---
    # Level and format depend on the debug flag.
    is_debug = app_config.get('app.debug', False)
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(logging.DEBUG if is_debug else logging.INFO)
    stream_handler.setFormatter(verbose_formatter if is_debug else console_formatter)
    logger.addHandler(stream_handler)

    # --- UI Log Handler ---
    # Shows PROGRESS, INFO, WARNING, ERROR, CRITICAL. Filters out DEBUG.
    if ui_callback:
        ui_handler = QLogHandler(level=PROGRESS_LEVEL_NUM)
        ui_handler.setFormatter(ui_formatter)
        ui_handler.log_received.connect(ui_callback)
        logger.addHandler(ui_handler)

    _logger_configured = True
    return logger

def get_logger(name):
    """Gets a pre-configured logger instance."""
    return logging.getLogger(name)

def create_task_logger(log_path):
    """
    Creates a dedicated logger for a single task that writes to its own file.
    This logger does not propagate to the root logger to avoid duplicate console/UI output.
    """
    task_logger = logging.getLogger(log_path) # Use log_path as a unique name
    task_logger.setLevel(logging.DEBUG)
    task_logger.propagate = False # Crucial: prevents messages from going to the root logger

    # If this logger has already been configured, just return it
    if task_logger.hasHandlers():
        return task_logger

    # Create a dedicated file handler for this task
    task_file_handler = RotatingFileHandler(log_path, maxBytes=5*1024*1024, backupCount=2, encoding='utf-8')
    task_file_handler.setLevel(logging.DEBUG)
    
    # Use a detailed formatter for the task log
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    task_file_handler.setFormatter(formatter)
    
    task_logger.addHandler(task_file_handler)
    
    return task_logger